home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / sendfax / sendfax.c++ < prev   
C/C++ Source or Header  |  1994-08-01  |  9KB  |  392 lines

  1. /*    $Header: /usr/people/sam/fax/sendfax/RCS/sendfax.c++,v 1.65 1994/04/08 03:58:22 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include "SendFaxClient.h"
  26. #include "FaxDB.h"
  27. #include "config.h"
  28.  
  29. #include "Dispatch/dispatcher.h"
  30.  
  31. #include <unistd.h>
  32. #include <stdlib.h>
  33. #include <stdarg.h>
  34. #include <paths.h>
  35. #include <pwd.h>
  36. #include <osfcn.h>
  37. extern "C" {
  38. #include <locale.h>
  39. }
  40.  
  41. class sendFaxApp : public SendFaxClient {
  42. private:
  43.     fxStr    appName;        // for error messages
  44.     fxStr    stdinTemp;        // temp file for collecting from pipe
  45.     FaxDB*    db;
  46.     int        verbose;
  47.     fxStr    company;
  48.     fxStr    location;
  49.  
  50.     static fxStr dbName;
  51.  
  52.     void addDestination(const char* cp);
  53.     void copyToTemporary(int fin, fxStr& tmpl);
  54.     fxStr tildeExpand(const fxStr& filename);
  55.     void printError(const char* va_alist ...);
  56.     void printWarning(const char* va_alist ...);
  57.     void fatal(const char* fmt ...);
  58.     void usage();
  59.  
  60.     virtual void recvConf(const char* cmd, const char* tag);
  61. public:
  62.     sendFaxApp();
  63.     ~sendFaxApp();
  64.  
  65.     fxBool initialize(int argc, char** argv);
  66. };
  67.  
  68. fxStr sendFaxApp::dbName("~/.faxdb");
  69.  
  70. sendFaxApp::sendFaxApp()
  71. {
  72.     db = NULL;
  73.     verbose = 0;
  74. }
  75.  
  76. sendFaxApp::~sendFaxApp()
  77. {
  78.     if (stdinTemp != "")
  79.     unlink((char*) stdinTemp);
  80.     delete db;
  81. }
  82.  
  83. fxBool
  84. sendFaxApp::initialize(int argc, char** argv)
  85. {
  86.     extern int optind;
  87.     extern char* optarg;
  88.     int c;
  89.  
  90.     appName = argv[0];
  91.     u_int l = appName.length();
  92.     appName = appName.tokenR(l, '/');
  93.  
  94.     db = new FaxDB(tildeExpand(dbName));
  95.     while ((c = getopt(argc, argv, "a:c:d:f:h:i:k:r:s:t:x:y:lmnpvDR")) != -1)
  96.     switch (c) {
  97.     case 'a':            // time at which to transmit job
  98.         setSendTime(optarg);
  99.         break;
  100.     case 'c':            // cover sheet: comment field
  101.         setCoverComments(optarg);
  102.         break;
  103.     case 'D':            // notify when done
  104.         setNotification(SendFaxClient::when_done);
  105.         break;
  106.     case 'd':            // destination name and number
  107.         addDestination(optarg);
  108.         break;
  109.     case 'f':            // sender's identity
  110.         setFromIdentity(optarg);
  111.         break;
  112.     case 'h':            // server's host
  113.         setHost(optarg);
  114.         break;
  115.     case 'i':            // user-specified job identifier
  116.         setJobTag(optarg);
  117.         break;
  118.     case 'k':            // time to kill job
  119.         setKillTime(optarg);
  120.         break;
  121.     case 'l':            // low resolution
  122.         setResolution(98.);
  123.         break;
  124.     case 'm':            // medium resolution
  125.         setResolution(196.);
  126.         break;
  127.     case 'n':            // no cover sheet
  128.         setCoverSheet(FALSE);
  129.         break;
  130.     case 'p':            // submit polling request
  131.         setPollRequest(TRUE);
  132.         break;
  133.     case 'r':            // cover sheet: regarding field
  134.         setCoverRegarding(optarg);
  135.         break;
  136.     case 'R':            // notify when requeued or done
  137.         setNotification(SendFaxClient::when_requeued);
  138.         break;
  139.     case 's':            // set page size
  140.         setPageSize(optarg);
  141.         break;
  142.     case 't':            // times to retry sending
  143.         setMaxRetries(atoi(optarg));
  144.         break;
  145.     case 'v':            // verbose mode
  146.         verbose++;
  147.         break;
  148.     case 'x':            // cover page: to's company
  149.         company = optarg;
  150.         break;
  151.     case 'y':            // cover page: to's location
  152.         location = optarg;
  153.         break;
  154.     case '?':
  155.         usage();
  156.         /*NOTREACHED*/
  157.     }
  158.     if (getNumberOfDestinations() == 0) {
  159.     fprintf(stderr, "%s: No destination specified.\n", (char*) appName);
  160.     usage();
  161.     }
  162.  
  163.     if (verbose)
  164.     setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
  165.     SendFaxClient::setVerbose(verbose > 0);    // type rules & basic operation
  166.     FaxClient::setVerbose(verbose > 1);        // protocol tracing
  167.  
  168.     if (optind < argc) {
  169.     for (; optind < argc; optind++)
  170.         addFile(argv[optind]);
  171.     } else if (!getPollRequest()) {
  172.     copyToTemporary(fileno(stdin), stdinTemp);
  173.     addFile(stdinTemp);
  174.     }
  175.     return (prepareSubmission() && submitJob());
  176. }
  177.  
  178. void
  179. sendFaxApp::usage()
  180. {
  181.     fxFatal("usage: %s"
  182.     " [-d destination]"
  183.     " [-h host[:modem]]"
  184.     " [-k kill-time]\n"
  185.     "    "
  186.     " [-a time-to-send]"
  187.     " [-c comments]"
  188.     " [-x company]"
  189.     " [-y location]"
  190.     " [-r regarding]\n"
  191.     "    "
  192.     " [-f from]"
  193.     " [-i identifier]"
  194.     " [-s pagesize]"
  195.     " [-t max-tries]"
  196.     " [-lmnpvDR]"
  197.     " [files]",
  198.     (char*) appName);
  199. }
  200.  
  201. /*
  202.  * Add a destination; parse ``person@number'' syntax.
  203.  */
  204. void
  205. sendFaxApp::addDestination(const char* cp)
  206. {
  207.     fxStr recipient;
  208.     const char* tp = strchr(cp, '@');
  209.     if (tp) {
  210.     recipient = fxStr(cp, tp-cp);
  211.     cp = tp+1;
  212.     } else
  213.     recipient = "";
  214.     fxStr dest(cp);
  215.     if (db && dest.length() > 0) {
  216.     fxStr name;
  217.     FaxDBRecord* r = db->find(dest, &name);
  218.     if (r) {
  219.         if (recipient == "")
  220.         recipient = name;
  221.         dest = r->find(FaxDB::numberKey);
  222.     }
  223.     }
  224.     if (dest.length() == 0)
  225.     fatal("Null destination for \"%s\"", cp);
  226.     if (!SendFaxClient::addDestination(recipient, dest, company, location))
  227.     fatal("Could not add fax destination");
  228. }
  229.  
  230. /*
  231.  * Expand a filename that might have `~' in it.
  232.  */
  233. fxStr
  234. sendFaxApp::tildeExpand(const fxStr& filename)
  235. {
  236.     fxStr path(filename);
  237.     if (filename.length() > 1 && filename[0] == '~') {
  238.     path.remove(0);
  239.     char* cp = getenv("HOME");
  240.     if (!cp || *cp == '\0') {
  241.         struct passwd* pwd = getpwuid(getuid());
  242.         if (!pwd)
  243.         fatal("Can not figure out who you are");
  244.         cp = pwd->pw_dir;
  245.     }
  246.     path.insert(cp);
  247.     }
  248.     return (path);
  249. }
  250.  
  251. /*
  252.  * Copy data from fin to a temporary file.
  253.  */
  254. void
  255. sendFaxApp::copyToTemporary(int fin, fxStr& tmpl)
  256. {
  257.     tmpl = _PATH_TMP "sndfaxXXXXXX";
  258.     int fd = mkstemp((char*) tmpl);
  259.     if (fd < 0)
  260.     fatal("%s: Can not create temporary file", (char*) tmpl);
  261.     int cc, total = 0;
  262.     char buf[16*1024];
  263.     while ((cc = read(fin, buf, sizeof (buf))) > 0) {
  264.     if (write(fd, buf, cc) != cc) {
  265.         unlink((char*) tmpl);
  266.         fatal("%s: write error", (char*) tmpl);
  267.     }
  268.     total += cc;
  269.     }
  270.     ::close(fd);
  271.     if (total == 0) {
  272.     unlink((char*) tmpl);
  273.     tmpl = "";
  274.     fatal("No input data; tranmission aborted");
  275.     }
  276. }
  277.  
  278. void
  279. sendFaxApp::printError(const char* va_alist ...)
  280. #define    fmt va_alist
  281. {
  282.     va_list ap;
  283.     va_start(ap, va_alist);
  284.     fprintf(stderr, "%s: ", (char*) appName);
  285.     vfprintf(stderr, fmt, ap);
  286.     va_end(ap);
  287.     fputs("\n", stderr);
  288.     exit(-1);
  289. }
  290. #undef fmt
  291.  
  292. void
  293. sendFaxApp::printWarning(const char* va_alist ...)
  294. #define    fmt va_alist
  295. {
  296.     va_list ap;
  297.     va_start(ap, va_alist);
  298.     fprintf(stderr, "%s: Warning, ", (char*) appName);
  299.     vfprintf(stderr, fmt, ap);
  300.     va_end(ap);
  301.     fputs("\n", stderr);
  302. }
  303. #undef fmt
  304.  
  305. #define    isCmd(s)    (strcasecmp(s, cmd) == 0)
  306.  
  307. void
  308. sendFaxApp::recvConf(const char* cmd, const char* tag)
  309. {
  310.     if (isCmd("job")) {
  311.     u_int len = getNumberOfFiles();
  312.     printf("request id is %s for host %s (%u %s)\n",
  313.         tag, (char*) getHost(), len, len > 1 ? "files" : "file");
  314.     } else if (isCmd("error")) {
  315.     printf("%s\n", tag);
  316.     } else
  317.     SendFaxClient::recvConf(cmd, tag);
  318. }
  319.  
  320. #include <signal.h>
  321. #include <setjmp.h>
  322.  
  323. static    sendFaxApp* app = NULL;
  324.  
  325. static void
  326. cleanup()
  327. {
  328.     sendFaxApp* a = app;
  329.     app = NULL;
  330.     delete a;
  331. }
  332.  
  333. static void
  334. sigDone(int)
  335. {
  336.     cleanup();
  337.     exit(-1);
  338. }
  339.  
  340. int
  341. main(int argc, char** argv)
  342. {
  343. #ifdef LC_CTYPE
  344.     setlocale(LC_CTYPE, "");
  345. #endif
  346.     signal(SIGHUP, fxSIGHANDLER(sigDone));
  347.     signal(SIGINT, fxSIGHANDLER(sigDone));
  348.     signal(SIGTERM, fxSIGHANDLER(sigDone));
  349.     app = new sendFaxApp;
  350.     if (!app->initialize(argc, argv))
  351.     sigDone(0);
  352.     while (app->isRunning())
  353.     Dispatcher::instance().dispatch();
  354.     signal(SIGHUP, fxSIGHANDLER(SIG_IGN));
  355.     signal(SIGINT, fxSIGHANDLER(SIG_IGN));
  356.     signal(SIGTERM, fxSIGHANDLER(SIG_IGN));
  357.     cleanup();
  358.     return (0);
  359. }
  360.  
  361. static void
  362. vfatal(FILE* fd, const char* fmt, va_list ap)
  363. {
  364.     vfprintf(fd, fmt, ap);
  365.     va_end(ap);
  366.     fputs(".\n", fd);
  367.     sigDone(0);
  368. }
  369.  
  370. void
  371. fxFatal(const char* va_alist ...)
  372. #define    fmt va_alist
  373. {
  374.     va_list ap;
  375.     va_start(ap, fmt);
  376.     vfatal(stderr, fmt, ap);
  377.     /*NOTTEACHED*/
  378. }
  379. #undef fmt
  380.  
  381. void
  382. sendFaxApp::fatal(const char* va_alist ...)
  383. #define    fmt va_alist
  384. {
  385.     fprintf(stderr, "%s: ", (char*) appName);
  386.     va_list ap;
  387.     va_start(ap, fmt);
  388.     vfatal(stderr, fmt, ap);
  389.     /*NOTTEACHED*/
  390. }
  391. #undef fmt
  392.